package com.yanqu.road.server.channelserver.manager.activity.washe.game;

import com.yanqu.road.entity.activity.washe.config.WasheConfig;
import com.yanqu.road.entity.activity.washe.eliminate.WasheBlock;
import com.yanqu.road.entity.activity.washe.eliminate.WasheCalcBombPosResult;
import com.yanqu.road.entity.activity.washe.eliminate.WasheGameData;
import com.yanqu.road.entity.activity.washe.eliminate.WasheMoveParam;
import com.yanqu.road.entity.activity.washe.eliminate.WasheShapeMatchResult;
import com.yanqu.road.entity.enums.washe.eWasheBlockType;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.Set;

public class WasheCreateBombLogic {

    /**
     * 获取生成的炸弹
     *
     * @param moveParam 可能为null
     */
    public static List<WasheBlock> getCreateBombList(WasheConfig config, int round, WasheMoveParam moveParam,
                                                     Set<WasheBlock> eliminateSet, Set<WasheBlock> dropSet, Random random,
                                                     List<WasheBlock> logAddStepBlockList, WasheGameData gameData) {
        List<WasheBlock> addBombList = new ArrayList<>();

        // 分组
        Map<Integer, List<List<WasheBlock>>> listListMap = groupEliminateSet(eliminateSet);

        // 遍历生成炸弹
        for (List<List<WasheBlock>> listList : listListMap.values()) {
            for (int i = 0; i < listList.size(); i++) {
                List<WasheBlock> list = listList.get(i);
                // 匹配形状
                WasheShapeMatchResult result = WasheShapeLogic.matchShape(list);
                if (result != null) {
                    // 生成炸弹
                    WasheBlock bombBlock = createBombBlock(result, round, moveParam, dropSet, random, gameData);
                    // 配置控制规则开关
                    if (config.getUseNewRule() == 0) {
                        // 剩余格子继续生成炸弹
                        list.removeAll(result.getUseBlockList());
                        if (!list.isEmpty()) {
                            i--;
                        }
                    }
                    addBombList.add(bombBlock);
                    // 记录下增加步数的炸弹
                    if (result.getUseBlockList().size() > logAddStepBlockList.size()) {
                        logAddStepBlockList.clear();
                        logAddStepBlockList.addAll(result.getUseBlockList());
                    }
                }
            }
        }

        return addBombList;
    }

    /**
     * 生成炸弹格子
     *
     * @param moveParam 可能为null
     */
    public static WasheBlock createBombBlock(WasheShapeMatchResult result,
                                             int round, WasheMoveParam moveParam,
                                             Set<WasheBlock> dropSet, Random random,
                                             WasheGameData gameData) {
        // 【找生成炸弹的位置】
        WasheCalcBombPosResult bombPosResult = calcCreateBombPos(result.getUseBlockList(), round, moveParam, dropSet);

        // 【计算炸弹类型】
        eWasheBlockType bombType = null;
        eWasheBlockType appointBombType = result.getShapeConfig().getShapeType().getAppointBombType();

        if (appointBombType != null) { // 指定形状
            bombType = appointBombType;
        } else if (result.getShapeConfig().getNeedCount() == 4) { // 单行4个：看交换方向，没有的就随机
            if (round == 1 && moveParam != null && bombPosResult.isContainsMoveBlock()) {
                bombType = moveParam.getFromY() == moveParam.getToY() ? eWasheBlockType.Hang : eWasheBlockType.Lie;
            } else {
                bombType = random.nextInt(1000) < 500 ? eWasheBlockType.Hang : eWasheBlockType.Lie;
            }
        }

        if (bombType == null) {
            bombType = eWasheBlockType.Normal;
        }

        // 生成炸弹格子
        WasheBlock posBlock = bombPosResult.getPosBlock();
        WasheBlock createBlock = new WasheBlock(posBlock.getX(), posBlock.getY(), posBlock.getColor());
        createBlock.setBlockType(bombType);
        WasheSceneLogic.scene_12_checkEffectChange(createBlock, gameData);
        return createBlock;
    }

    /**
     * 计算炸弹生成位置
     *
     * @param moveParam 可能为null
     */
    private static WasheCalcBombPosResult calcCreateBombPos(List<WasheBlock> useBlock,
                                                            int round, WasheMoveParam moveParam,
                                                            Set<WasheBlock> dropSet) {
        // 第一轮 && 移动 && 包含交换的格子
        boolean firstRound = round == 1;
        if (firstRound && moveParam != null) {
            Optional<WasheBlock> any = useBlock.stream().filter(item -> item.getX() == moveParam.getToX() && item.getY() == moveParam.getToY()).findAny();
            if (any.isPresent()) {
                return new WasheCalcBombPosResult(any.get(), true);
            }
            any = useBlock.stream().filter(item -> item.getX() == moveParam.getFromX() && item.getY() == moveParam.getFromY()).findAny();
            if (any.isPresent()) {
                return new WasheCalcBombPosResult(any.get(), true);
            }
        }

        // 包含掉落格子（useBlock是小到大排序的）
        for (WasheBlock block : useBlock) {
            if (dropSet.contains(block)) {
                return new WasheCalcBombPosResult(block, false);
            }
        }

        return new WasheCalcBombPosResult(useBlock.get(0), false);
    }

    /**
     * 消除的方块按颜色、相邻分组
     */
    public static Map<Integer, List<List<WasheBlock>>> groupEliminateSet(Set<WasheBlock> eliminateSet) {
        // 搞个空的盘面数据
        List<List<WasheBlock>> blockList = WasheGameLogic.getEmptyBlockList();
        // 填充一下
        for (WasheBlock block : eliminateSet) {
            if(!WasheGameLogic.isBaseFourBigType(block)){
                continue;
            }
            blockList.get(block.getY()).set(block.getX(), block);
        }

        Map<Integer, List<List<WasheBlock>>> listListMap = new HashMap<>();

        for (WasheBlock block : eliminateSet) {
            // 跳过没颜色的
            if (block.getColor() == 0) {
                continue;
            }
            if (!WasheGameLogic.canSameColorEliminate(blockList, block)) {
                continue;
            }

            listListMap.putIfAbsent(block.getColor(), new ArrayList<>());
            List<List<WasheBlock>> listList = listListMap.get(block.getColor());

            // 和该方块相邻的方块位于list的哪些下标
            List<Integer> adjoinIndexList = new ArrayList<>();
            for (int i = 0; i < listList.size(); i++) {
                List<WasheBlock> list = listList.get(i);
                for (WasheBlock tmpBlock : list) {
                    if (tmpBlock.getColor() == block.getColor() && isBlockAdjoin(tmpBlock, block)) {
                        adjoinIndexList.add(i);
                        break;
                    }
                }
            }

            // 相邻的合并起来
            List<WasheBlock> list = new ArrayList<>();
            list.add(block);
            for (Integer index : adjoinIndexList) {
                list.addAll(listList.get(index));
            }
            for (int i = adjoinIndexList.size() - 1; i >= 0; i--) {
                listList.remove((int) adjoinIndexList.get(i));
            }
            listList.add(list);
        }

        // 排个序吧，按位置小到大
        for (List<List<WasheBlock>> listList : listListMap.values()) {
            for (List<WasheBlock> list : listList) {
                list.sort(new Comparator<WasheBlock>() {
                    @Override
                    public int compare(WasheBlock o1, WasheBlock o2) {
                        if (o1.getY() != o2.getY()) {
                            return o1.getY() - o2.getY();
                        } else if (o1.getX() != o2.getX()) {
                            return o1.getX() - o2.getX();
                        } else {
                            return 0;
                        }
                    }
                });
            }
        }

        return listListMap;
    }

    /**
     * 方块是否相邻（可斜消时斜着的也算相邻）
     */
    private static boolean isBlockAdjoin(WasheBlock block1, WasheBlock block2) {
        int subY = Math.abs(block1.getY() - block2.getY());
        int subX = Math.abs(block1.getX() - block2.getX());
        return subX + subY == 1;
    }

}
